package ink.xiaobaibai.controller.free;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import ink.xiaobaibai.common.FreeClientUserStatus;
import ink.xiaobaibai.common.MySecurity;
import ink.xiaobaibai.common.OpenFreeDevicePost;
import ink.xiaobaibai.common.RoomObj;
import ink.xiaobaibai.entity.FreeClientUser;
import ink.xiaobaibai.entity.FreeOzoneDevice;
import ink.xiaobaibai.response.ResponseFormat;
import ink.xiaobaibai.service.IFreeClientUserService;
import ink.xiaobaibai.service.IFreeOzoneDeviceService;
import ink.xiaobaibai.serviceOxy.free.IDeviceFreeControlService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @description: 免费机器
 * @author: 小白白
 * @create: 2021-07-21
 **/

@RestController
@RequestMapping("/free/device")
@Api(tags = "酒店免费业务机器控制层")
public class FreeDeviceController {

    @Autowired
    private IFreeOzoneDeviceService freeOzoneDeviceService;

    @Autowired
    private IFreeClientUserService freeClientUserService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private IDeviceFreeControlService deviceFreeControlService;

    private final static String FREE_DEVICE_RECORD = "free_record:";

    @GetMapping("/identity")
    @ApiOperation("是否可以操作免费机器 || 返回boolean值,表明当前用户是否有可以操作的机器")
    public ResponseFormat identity() {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<FreeClientUser> q1 = new QueryWrapper<>();
        q1.eq("client_user_id", userId);
        q1.eq("status", FreeClientUserStatus.OK.getStatus());
        q1.last(" limit 1 ");
        return ResponseFormat.success(this.freeClientUserService.count(q1) != 0);
    }

    @GetMapping("/room-list")
    @ApiOperation("查询自己可以操纵的房间信息")
    public ResponseFormat roomList() {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<FreeClientUser> q1 = new QueryWrapper<>();
        q1.select("id", "room_obj_list", "device_id");
        q1.eq("status", FreeClientUserStatus.OK.getStatus());
        q1.eq("client_user_id", userId);
        List<FreeClientUser> clientUserList = this.freeClientUserService.list(q1);
        List<Integer> ids = clientUserList.stream().map(c -> c.getDeviceId()).collect(Collectors.toList());
        QueryWrapper<FreeOzoneDevice> q2 = new QueryWrapper<>();
        q2.select("id", "device_code");
        q2.in("id", ids);
        List<FreeOzoneDevice> list = this.freeOzoneDeviceService.list(q2);
        Map<Integer, String> map = new HashMap<>(list.size());
        for (FreeOzoneDevice freeOzoneDevice : list) {
            map.put(freeOzoneDevice.getId(), freeOzoneDevice.getDeviceCode());
        }
        for (FreeClientUser freeClientUser : clientUserList) {
            freeClientUser.setDeviceCode(map.get(freeClientUser.getDeviceId()));
            for (RoomObj roomObj : freeClientUser.getRoomObjList()) {
                String stopTime = this.getRoomDeviceStopTime(freeClientUser.getId(), roomObj.getRoom());
                if (stopTime != null) {
                    roomObj.setStopTime(stopTime);
                    roomObj.setOpen(true);
                }
            }
        }
        return ResponseFormat.success(clientUserList);
    }

    /**
     * 启动机器
     */
    @PostMapping("/open")
    @ApiOperation("启动机器 || 传入 id 和 房间号")
    public ResponseFormat openDevice(@RequestBody @Validated OpenFreeDevicePost openFreeDevicePost) {
        Integer userId = MySecurity.getUserId();
        Integer id = openFreeDevicePost.getId();
        String roomNumber = openFreeDevicePost.getRoomNumber();
        FreeClientUser freeClientUser = this.freeClientUserService.getById(id);
        if (!freeClientUser.getStatus().equals(FreeClientUserStatus.OK.getStatus())) {
            return ResponseFormat.fail("未审核通过,不可启动");
        }
        if (!freeClientUser.getRoomObjList().contains(new RoomObj(roomNumber))) {
            return ResponseFormat.fail("当前房间号不存在");
        }
        if (!freeClientUser.getClientUserId().equals(userId)) {
            return ResponseFormat.fail("无权限");
        }

        // 机器房间是否设置一天一次的判断
        QueryWrapper<FreeOzoneDevice> q1 = new QueryWrapper<>();
        q1.select("single_room_number");
        q1.eq("id", freeClientUser.getDeviceId());
        List<String> singleRoomNumber = this.freeOzoneDeviceService.getOne(q1).getSingleRoomNumber();
        if (singleRoomNumber.contains(roomNumber)) {
            // 开始判断今天是否已经启动过一次了
            if (!this.singleJudgmentOkGo(freeClientUser.getDeviceId(), roomNumber)) {
                return ResponseFormat.fail("此房间今天以及执行过一次了");
            }
        }

        RoomObj roomObjItem = null;
        // 当天服务员启动次数的判断
        Set<RoomObj> roomObjList = freeClientUser.getRoomObjList();
        for (RoomObj roomObj : roomObjList) {
            if (roomObj.getRoom().equals(roomNumber)) {
                // 内部已经增加今天的次数
                if (!this.judgmentCountGo(freeClientUser.getDeviceId(), roomNumber, roomObj.getCount())) {
                    return ResponseFormat.fail("您的执行次数已达到上线");
                }
                roomObjItem = roomObj;
                break;
            }
            // 也可能当前机器没这个房,不过那也算了
        }

        if (roomObjItem == null) {
            return ResponseFormat.fail("房间号不存在");
        }

        this.deviceFreeControlService.open(freeClientUser.getDeviceId(), openFreeDevicePost.getRoomNumber(), roomObjItem.getSeconds());
        this.openRecord(openFreeDevicePost.getId(), openFreeDevicePost.getRoomNumber(), roomObjItem.getSeconds());

        return ResponseFormat.success();
    }

    @GetMapping("/close")
    @ApiOperation("关闭机器 || 传入机器id+房间号")
    public ResponseFormat closeDevice(@RequestParam("deviceId") Integer id,
                                      @RequestParam("room") String room) {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<FreeClientUser> q1 = new QueryWrapper<>();
        q1.eq("device_id", id);
        q1.eq("client_user_id", userId);
        FreeClientUser freeClientUser = this.freeClientUserService.getOne(q1);
        if (!freeClientUser.getStatus().equals(FreeClientUserStatus.OK.getStatus())) {
            return ResponseFormat.fail("未审核通过,不可关闭");
        }
        if (!freeClientUser.getRoomObjList().contains(new RoomObj(room))) {
            return ResponseFormat.fail("当前房间号不存在");
        }
        if (!freeClientUser.getClientUserId().equals(userId)) {
            return ResponseFormat.fail("无权限");
        }
        this.deviceFreeControlService.close(id, room);
        this.closeRecord(id, room);
        return ResponseFormat.success();
    }

    private boolean singleJudgmentOkGo(Integer deviceId, String roomNumber) {
        final String singleRoomPre = "singleRoomPre:";
        String key = singleRoomPre + deviceId + ":" + roomNumber;
        String value = this.stringRedisTemplate.opsForValue().get(key);
        Calendar calendar = Calendar.getInstance();
        String day = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
        if (value == null || !value.equals(day)) {
            // 可以执行
            this.stringRedisTemplate.opsForValue().set(key, day, 24, TimeUnit.HOURS);
            return true;
        }
        // 不可执行
        return false;
    }

    private boolean judgmentCountGo(Integer deviceId, String roomNumber, Integer allCount) {
        final String countRoomPre = "countRoomPre:";
        String key = countRoomPre + deviceId + ":" + roomNumber;
        String value = this.stringRedisTemplate.opsForValue().get(key);
        Calendar calendar = Calendar.getInstance();
        String day = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
        if (value == null) {
            value = day + "@" + 1;
            this.stringRedisTemplate.opsForValue().set(key, value, 24, TimeUnit.HOURS);
            return true;
        } else {
            String[] split = value.split("@");
            if (split[0].equals(day)) {
                int count = Integer.parseInt(split[1]);
                if (count == allCount) {
                    return false;
                }
                // 当前天
                value = split[0] + (count + 1);
                this.stringRedisTemplate.opsForValue().set(key, value, 24, TimeUnit.HOURS);
                return true;
            } else {
                // 非当前天
                value = day + "@" + 1;
                this.stringRedisTemplate.opsForValue().set(key, value, 24, TimeUnit.HOURS);
                return true;
            }
        }
    }

    /**
     * 开启当前机器房间记录
     */
    private void openRecord(Integer deviceId, String roomNumber, Integer seconds) {
        this.stringRedisTemplate.opsForValue().set(FREE_DEVICE_RECORD + deviceId + "@" + roomNumber, DateUtils.addSeconds(new Date(), seconds).toString(), seconds, TimeUnit.SECONDS);
    }

    /**
     * 关闭当前机器房间
     */
    private void closeRecord(Integer deviceId, String roomNumber) {
        this.stringRedisTemplate.delete(FREE_DEVICE_RECORD + deviceId + "@" + roomNumber);
    }

    /**
     * 查询当前机器房间的停止时间(null则表明机器关闭中)
     */
    private String getRoomDeviceStopTime(Integer deviceId, String roomNumber) {
        return this.stringRedisTemplate.opsForValue().get(FREE_DEVICE_RECORD + deviceId + "@" + roomNumber);
    }

}
